import { Inject, Injectable } from '@nestjs/common';
import { io, Socket } from 'socket.io-client';
import { Logger } from '@nestjs/common';
import { generateSignature } from 'src/utils/signature';
import { ConfigService } from '@nestjs/config';
import { parseMsg } from 'src/utils/helper';
import { awaitTime } from 'src/utils/time';
// import { ScriptService } from 'src/modules/script/script.service';
/**
 * Socket.IO 客户端类
 */
@Injectable()
export class SocketService {
  private socket: Socket;
  private roomId: string | null = null;
  private device: string;
  private serverUrl: string;
  private connected = false;
  private errorConnectMax = 10; // 连接错误次数
  logger = new Logger(SocketService.name);

  constructor(
    @Inject(ConfigService) private readonly configService: ConfigService,
  ) {
    this.init();
  }
  private init(): void {
    const serverUrl = this.configService.get<string>(
      'SOCKET_SERVER_URL',
    ) as string;
    const device = this.configService.get<string>('SOCKET_DEVICE_ID') as string;
    if (!device) {
      throw new Error('设备ID不能为空');
    }
    const room = this.configService.get<string>('SOCKET_ROOM_ID') as string;

    this.device = device;
    this.serverUrl = serverUrl;
    this.logger.log(`ws 🔌 设备ID: ${device}`, `链接地址：${this.serverUrl}`);
    const connectionParams = generateSignature({ device, room });
    this.socket = io(this.serverUrl, {
      reconnection: true,
      reconnectionAttempts: 5,
      reconnectionDelay: 1000,
      transports: ['websocket'],
      query: connectionParams,
      auth: connectionParams,
    });

    this.setupEventListeners();
  }
  /**
   * 设置事件监听器
   */
  private setupEventListeners(): void {
    // 连接成功事件
    this.socket.on('connect', () => {
      this.connected = true;
      this.logger.log(`✅ 已连接到ws服务器 ${this.serverUrl}`);
      this.logger.log(`🔌 Socket ID: ${this.socket.id}`);
    });

    // 连接断开事件
    this.socket.on('disconnect', (reason: string) => {
      this.connected = false;
      this.logger.log(`⚠️ 连接断开: ${reason}`);
      if (reason === 'io server disconnect') {
        this.logger.log('🔄 尝试重新连接...');
        this.socket.connect();
      }
    });
    // let errorCount = 0;
    // 连接错误事件
    this.socket.on('connect_error', async (error: Error) => {
      this.logger.log(`❌ 连接错误: ${error.message}`);
      await awaitTime(5000);
      this.logger.log('🔄 尝试重新连接...');
      const room = this.configService.get<string>('SOCKET_ROOM_ID') as string;
      this.socket.auth = generateSignature({
        device: this.device,
        room,
      });
      this.socket.connect();
    });

    process.on('exit', () => {
      this.socket.disconnect();
    });

    // 系统广播消息
    this.socket.on('system', (data: any) => {
      this.logger.log(`📢 系统消息: ${JSON.stringify(data)}`);
    });

    // 通知消息
    this.socket.on('notification', (data: any) => {
      this.logger.log(`📨 通知消息: ${JSON.stringify(data)}`);
    });

    // 房间消息
    this.socket.on('room_message', (data: any) => {
      this.logger.log(`🏠 房间消息 [${this.roomId}]: ${JSON.stringify(data)}`);
    });

    // 加入房间确认
    this.socket.on('join_confirm', (roomId: string) => {
      this.logger.log(`🎉 成功加入房间: ${roomId}`);
      this.roomId = roomId;
    });

    // 离开房间确认
    this.socket.on('leave_confirm', (roomId: string) => {
      this.logger.log(`🚪 离开房间: ${roomId}`);
      if (this.roomId === roomId) {
        this.roomId = null;
      }
    });
  }

  /**
   * 加入房间
   * @param roomId 房间ID
   */
  joinRoom(roomId: string): void {
    if (!this.connected) {
      this.logger.log('❌ 尚未连接到服务器，无法加入房间');
      return;
    }
    this.logger.log(`🔑 尝试加入房间: ${roomId}`);
    this.socket.emit('join', roomId);
  }

  /**
   * 离开房间
   * @param roomId 房间ID
   */
  leaveRoom(roomId: string): void {
    if (!this.connected) {
      this.logger.log('❌ 尚未连接到服务器，无法离开房间');
      return;
    }
    this.logger.log(`🚪 尝试离开房间: ${roomId}`);
    this.socket.emit('leave', roomId);
  }

  /**
   * 发送消息到房间
   * @param message 消息内容
   */
  sendRoomMessage(message: string): void {
    if (!this.connected || !this.roomId) {
      this.logger.log('❌ 未加入任何房间，无法发送消息');
      return;
    }
    this.logger.log(`✉️ 发送消息到房间 ${this.roomId}: ${message}`);
    this.socket.emit('room_message', {
      roomId: this.roomId,
      message,
      timestamp: new Date().toISOString(),
    });
  }

  /**
   * 断开连接
   */
  disconnect(): void {
    if (this.connected) {
      this.logger.log('🔌 正在断开连接...');
      this.socket.disconnect();
    }
  }

  emit(event: string, ...args: any[]): void {
    this.socket.emit(event, parseMsg(event, args[0]));
  }

  on(
    event: string,
    // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
    callback: (...args: any[]) => void | Promise<any> | any,
  ): void {
    // eslint-disable-next-line @typescript-eslint/no-this-alias
    const cur = this;
    async function useCb(...args: any[]) {
      try {
        // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-argument
        const res = await callback(...args);
        if (res) {
          void cur.emit(`${event}_success`, res);
        }
      } catch (error) {
        cur.logger.error(error);
        void cur.emit(`${event}_fail`, (error as Error).message);
      }
    }
    if (!this.connected) {
      this.socket.once('connect', () => {
        this.socket.on(event, useCb);
      });
    } else {
      this.socket.on(event, useCb);
    }

    return this.off(event, useCb);
  }

  off(event: string, callback: (...args: any[]) => void | Promise<any>): void {
    this.socket.off(event, callback);
  }
}
